package com.utry.netty.websocket;

import android.util.Log;

import com.utry.netty.bean.PkgDataBean;
import com.utry.netty.client.NettyClient;
import com.utry.netty.intf.ConnectClientCallback;
import com.utry.netty.intf.MessageClientCallback;

import java.util.concurrent.TimeUnit;

import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelPromise;
import io.netty.channel.EventLoop;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.FullHttpResponse;
import io.netty.handler.codec.http.websocketx.BinaryWebSocketFrame;
import io.netty.handler.codec.http.websocketx.CloseWebSocketFrame;
import io.netty.handler.codec.http.websocketx.PongWebSocketFrame;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import io.netty.handler.codec.http.websocketx.WebSocketClientHandshaker;
import io.netty.handler.codec.http.websocketx.WebSocketFrame;
import io.netty.handler.codec.http.websocketx.WebSocketHandshakeException;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;
import io.netty.util.CharsetUtil;

public class MockClientHandler extends SimpleChannelInboundHandler<Object> {
    private static final String TAG = MockClientHandler.class.getSimpleName();
    //握手的状态信息
    WebSocketClientHandshaker handshaker;
    //netty自带的异步处理
    ChannelPromise handshakeFuture;

    private NettyStocktakingClient client;
    private MessageClientCallback messageClientCallback;
    private ConnectClientCallback connectCallback;

    public MockClientHandler(NettyStocktakingClient nettyClient, ConnectClientCallback connectCallback) {
        this.client = nettyClient;
        this.connectCallback = connectCallback;
    }

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, Object msg) throws Exception {
        Log.v(TAG,"当前握手的状态" + this.handshaker.isHandshakeComplete());
        Channel ch = ctx.channel();
        FullHttpResponse response;
        //进行握手操作
        if (!this.handshaker.isHandshakeComplete()) {
            try {
                response = (FullHttpResponse) msg;
                //握手协议返回，设置结束握手
                this.handshaker.finishHandshake(ch, response);
                //设置成功
                this.handshakeFuture.setSuccess();
                Log.v(TAG,"服务端的消息" + response.headers());
//                Log.v(TAG,"服务端的消息" + response.headers());
            } catch (WebSocketHandshakeException var7) {
                FullHttpResponse res = (FullHttpResponse) msg;
                String errorMsg = String.format("握手失败,status:%s,reason:%s", res.status(), res.content().toString(CharsetUtil.UTF_8));
                this.handshakeFuture.setFailure(new Exception(errorMsg));
            }
        } else if (msg instanceof FullHttpResponse) {
            response = (FullHttpResponse) msg;
            throw new IllegalStateException("Unexpected FullHttpResponse (getStatus=" + response.status() + ", content=" + response.content().toString(CharsetUtil.UTF_8) + ')');
        } else {
            //接收服务端的消息
            WebSocketFrame frame = (WebSocketFrame) msg;
            //文本信息
            if (frame instanceof TextWebSocketFrame) {
                TextWebSocketFrame textFrame = (TextWebSocketFrame) frame;
                Log.v(TAG,"客户端接收的消息是:" + textFrame.text());
                if (null != messageClientCallback) {
                    messageClientCallback.messageClientCallback(textFrame.text());
                }
            }
            //二进制信息
            if (frame instanceof BinaryWebSocketFrame) {
                BinaryWebSocketFrame binFrame = (BinaryWebSocketFrame) frame;
                Log.v(TAG,"BinaryWebSocketFrame");
            }
            //ping信息
            if (frame instanceof PongWebSocketFrame) {
                Log.v(TAG,"WebSocket Client received pong");
            }
            //关闭消息
            if (frame instanceof CloseWebSocketFrame) {
                Log.v(TAG,"receive close frame");
                ch.close();
            }

        }
    }

    /**
     * Handler活跃状态，表示连接成功
     *
     * @param ctx
     * @throws Exception
     */
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        Log.v(TAG,"与服务端连接成功");
        if (null != connectCallback) {
            connectCallback.onConnect(0, "与服务端连接成功：" + ctx.toString());
        }
    }

    /**
     * 非活跃状态，没有连接远程主机的时候。
     *
     * @param ctx
     * @throws Exception
     */
    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        Log.v(TAG,"主机关闭");
        if (null != connectCallback) {
            connectCallback.onConnect(1, "与服务端断开连接：" + ctx.toString());
        }
        //启动重连
        reConnect(ctx);
    }


    /**
     * 5s重连一次服务端
     *
     * @param ctx
     */
    private void reConnect(final ChannelHandlerContext ctx) {
        EventLoop loop = ctx.channel().eventLoop();
        loop.schedule(() -> {
            Log.d(TAG, "连接断开，发起重连");
            if (null != connectCallback) {
                connectCallback.onConnect(1, "连接断开，发起重连：" + ctx.toString());
            }
            client.connectNetty();
        }, 5, TimeUnit.SECONDS);
    }

    /**
     * 异常处理
     *
     * @param ctx
     * @param cause
     * @throws Exception
     */
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        Log.v(TAG,"连接异常：" + cause.getMessage());
        ctx.close();
    }

    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        if (evt instanceof IdleStateEvent) {
            if (((IdleStateEvent) evt).state() == IdleState.READER_IDLE) {
                sendHeartPkg(ctx);
            }
        }
        super.userEventTriggered(ctx, evt);
    }

    /**
     * 发送心跳
     */
    private void sendHeartPkg(ChannelHandlerContext ctx) {
        PkgDataBean bean = new PkgDataBean();
        bean.setCmd((byte) 0x02);
        bean.setData("心跳数据包");
        bean.setDataLength((byte) bean.getData().getBytes().length);
        ctx.channel().writeAndFlush(bean);
        Log.d(TAG, "客户端发送心跳成功");
    }

    public void handlerAdded(ChannelHandlerContext ctx) {
        this.handshakeFuture = ctx.newPromise();
    }

    public WebSocketClientHandshaker getHandshaker() {
        return handshaker;
    }

    public void setHandshaker(WebSocketClientHandshaker handshaker) {
        this.handshaker = handshaker;
    }

    public ChannelPromise getHandshakeFuture() {
        return handshakeFuture;
    }

    public void setHandshakeFuture(ChannelPromise handshakeFuture) {
        this.handshakeFuture = handshakeFuture;
    }

    public ChannelFuture handshakeFuture() {
        return this.handshakeFuture;
    }

    public void setMessageClientCallback(MessageClientCallback messageClientCallback) {
        this.messageClientCallback = messageClientCallback;
    }
}
